//////////////////////////////////////////////////////////////////////////
#include "CvColors.h"
#include "CxTypes.Classes.Managed.h"
//////////////////////////////////////////////////////////////////////////
#pragma once
#pragma managed
//////////////////////////////////////////////////////////////////////////
using namespace System::Runtime::InteropServices;
//////////////////////////////////////////////////////////////////////////
NAMESPACE_BEGIN
//////////////////////////////////////////////////////////////////////////
generic<typename TPixel> where TPixel : value struct, IColor
public interface class IManagedArrPixelAccessor
{
	property TPixel default[int, int]
	{
		TPixel get(int row, int col);											
		void set(int row, int col, TPixel value);
	}
};

template<typename TPixel>
public ref class ManagedArrPixelAccessorBase abstract : public IManagedArrPixelAccessor<TPixel>
{
public:																					
	ManagedArrPixelAccessorBase(ManagedImage^ image)								
	{																					
		m_pScan0 = (char*)(image->ToIplImagePointer()->imageData);
		m_nStride = image->ToIplImagePointer()->widthStep;
	}

	ManagedArrPixelAccessorBase(ManagedMat^ mat)								
	{																					
		m_pScan0 = (char*)(mat->ToCvMatPointer()->data.ptr);
		m_nStride = mat->ToCvMatPointer()->step;
	}

	property virtual TPixel default[int, int]										
	{																					
		TPixel get(int row, int col)											
		{																				
			return ((TPixel*)(m_pScan0 + row * m_nStride))[col];				
		}																				
		void set(int row, int col, TPixel value)								
		{																				
			((TPixel*)(m_pScan0 + row * m_nStride))[col] = value;				
		}																				
	}

private:																				
	char* m_pScan0;
	int m_nStride;
};

generic<typename TPixel> where TPixel : value struct, IColor
public ref class ManagedArrPixelAccessor : public IManagedArrPixelAccessor<TPixel>
{
public:																					
	ManagedArrPixelAccessor(ManagedImage^ image)								
	{																					
		m_pScan0 = (char*)(image->ToIplImagePointer()->imageData);
		m_nStride = image->ToIplImagePointer()->widthStep;
	}

	ManagedArrPixelAccessor(ManagedMat^ mat)								
	{																					
		m_pScan0 = (char*)(mat->ToCvMatPointer()->data.ptr);
		m_nStride = mat->ToCvMatPointer()->step;
	}

	property virtual TPixel default[int, int]										
	{	
		TPixel get(int row, int col)										
		{
			TPixel ret;
			Marshal::PtrToStructure(IntPtr(m_pScan0 + row * m_nStride + sizeof(TPixel) * col), ret);
			return ret;
		}																				
		void set(int row, int col, TPixel value)							
		{
			Marshal::StructureToPtr(value, IntPtr(m_pScan0 + row * m_nStride + sizeof(TPixel) * col), false);
		}																				
	}

private:																				
	char* m_pScan0;
	int m_nStride;
};

#define MANAGED_ARR_PIXEL_ACCESOR(NAME, TEMPLATE, ELEMENT)									\
	public ref class ManagedArrPixelAccessor##NAME											\
		: public ManagedArrPixelAccessorBase<TEMPLATE<ELEMENT>>								\
	{																						\
	public:																					\
		ManagedArrPixelAccessor##NAME(ManagedImage^ image)									\
		: ManagedArrPixelAccessorBase<TEMPLATE<ELEMENT>>(image) {}							\
		ManagedArrPixelAccessor##NAME(ManagedMat^ mat)										\
		: ManagedArrPixelAccessorBase<TEMPLATE<ELEMENT>>(mat) {}							\
	}

#define MANAGED_ARR_PIXEL_ACCESOR_GROUP(TEMPLATE)											\
	MANAGED_ARR_PIXEL_ACCESOR(TEMPLATE##8U, TEMPLATE, unsigned char);						\
	MANAGED_ARR_PIXEL_ACCESOR(TEMPLATE##8S, TEMPLATE, signed char);							\
	MANAGED_ARR_PIXEL_ACCESOR(TEMPLATE##16U, TEMPLATE, unsigned short);						\
	MANAGED_ARR_PIXEL_ACCESOR(TEMPLATE##16S, TEMPLATE, signed short);						\
	MANAGED_ARR_PIXEL_ACCESOR(TEMPLATE##32S, TEMPLATE, signed int);							\
	MANAGED_ARR_PIXEL_ACCESOR(TEMPLATE##32F, TEMPLATE, float);								\
	MANAGED_ARR_PIXEL_ACCESOR(TEMPLATE##64F, TEMPLATE, double)

MANAGED_ARR_PIXEL_ACCESOR_GROUP(Gray);
MANAGED_ARR_PIXEL_ACCESOR_GROUP(Bgr);
MANAGED_ARR_PIXEL_ACCESOR_GROUP(Bgra);
MANAGED_ARR_PIXEL_ACCESOR_GROUP(Rgb);
MANAGED_ARR_PIXEL_ACCESOR_GROUP(Rgba);
MANAGED_ARR_PIXEL_ACCESOR_GROUP(Xyz);
MANAGED_ARR_PIXEL_ACCESOR_GROUP(YCrCb);
MANAGED_ARR_PIXEL_ACCESOR_GROUP(Hsv);
MANAGED_ARR_PIXEL_ACCESOR_GROUP(Lab);
MANAGED_ARR_PIXEL_ACCESOR_GROUP(Luv);
MANAGED_ARR_PIXEL_ACCESOR_GROUP(Hls);

generic<typename T> where T : value struct
public interface class IManagedArrElementAccessor
{
	property T default[int, int, int]
	{
		T get(int row, int col, int channel);											
		void set(int row, int col, int channel, T value);
	}
};

template<typename T>
public ref class ManagedArrElementAccessorBase abstract : public IManagedArrElementAccessor<T>
{
public:																					
	ManagedArrElementAccessorBase(ManagedImage^ image)								
	{																					
		m_pScan0 = (char*)(image->ToIplImagePointer()->imageData);
		m_nStride = image->ToIplImagePointer()->widthStep;
		m_nChannels = image->ToIplImagePointer()->nChannels;
	}

	ManagedArrElementAccessorBase(ManagedMat^ mat)								
	{																					
		m_pScan0 = (char*)(mat->ToCvMatPointer()->data.ptr);
		m_nStride = mat->ToCvMatPointer()->step;
		m_nChannels = CV_MAT_CN(mat->ToCvMatPointer()->type);
	}

	property virtual T default[int, int, int]												
	{																					
		T get(int row, int col, int channel)										
		{																				
			return ((T*)(m_pScan0 + row * m_nStride))[col * m_nChannels + channel];			
		}																				
		void set(int row, int col, int channel, T value)							
		{																				
			((T*)(m_pScan0 + row * m_nStride))[col * m_nChannels + channel] = value;			
		}																				
	}	

private:																				
	char* m_pScan0;
	int m_nStride;
	int m_nChannels;
};

generic<typename T> where T : value struct
public ref class ManagedArrElementAccessor : public IManagedArrElementAccessor<T>
{
public:																					
	ManagedArrElementAccessor(ManagedImage^ image)								
	{																					
		m_pScan0 = (char*)(image->ToIplImagePointer()->imageData);
		m_nStride = image->ToIplImagePointer()->widthStep;
		m_nChannels = image->ToIplImagePointer()->nChannels;
	}

	ManagedArrElementAccessor(ManagedMat^ mat)								
	{																					
		m_pScan0 = (char*)(mat->ToCvMatPointer()->data.ptr);
		m_nStride = mat->ToCvMatPointer()->step;
		m_nChannels = CV_MAT_CN(mat->ToCvMatPointer()->type);
	}
																				
	property virtual T default[int, int, int]												
	{																					
		T get(int row, int col, int channel)										
		{
			T ret;
			Marshal::PtrToStructure(IntPtr(m_pScan0 + row * m_nStride + sizeof(T) * (col * m_nChannels + channel)), ret);
			return ret;
		}																				
		void set(int row, int col, int channel, T value)							
		{
			Marshal::StructureToPtr(value, IntPtr(m_pScan0 + row * m_nStride + sizeof(T) * (col * m_nChannels + channel)), false);
		}																				
	}	

private:																				
	char* m_pScan0;
	int m_nStride;
	int m_nChannels;
};

public ref class ManagedArrElementAccessor8U : ManagedArrElementAccessorBase<unsigned char>
{
public:
	ManagedArrElementAccessor8U(ManagedMat^ mat) : ManagedArrElementAccessorBase<unsigned char>(mat) {}
	ManagedArrElementAccessor8U(ManagedImage^ image) : ManagedArrElementAccessorBase<unsigned char>(image) {}
};

public ref class ManagedArrElementAccessor8S : ManagedArrElementAccessorBase<char>
{
public:
	ManagedArrElementAccessor8S(ManagedMat^ mat) : ManagedArrElementAccessorBase<char>(mat) {}
	ManagedArrElementAccessor8S(ManagedImage^ image) : ManagedArrElementAccessorBase<char>(image) {}
};

public ref class ManagedArrElementAccessor16U : ManagedArrElementAccessorBase<unsigned short>
{
public:
	ManagedArrElementAccessor16U(ManagedMat^ mat) : ManagedArrElementAccessorBase<unsigned short>(mat) {}
	ManagedArrElementAccessor16U(ManagedImage^ image) : ManagedArrElementAccessorBase<unsigned short>(image) {}
};

public ref class ManagedArrElementAccessor16S : ManagedArrElementAccessorBase<short>
{
public:
	ManagedArrElementAccessor16S(ManagedMat^ mat) : ManagedArrElementAccessorBase<short>(mat) {}
	ManagedArrElementAccessor16S(ManagedImage^ image) : ManagedArrElementAccessorBase<short>(image) {}
};

public ref class ManagedArrElementAccessor32S : ManagedArrElementAccessorBase<int>
{
public:
	ManagedArrElementAccessor32S(ManagedMat^ mat) : ManagedArrElementAccessorBase<int>(mat) {}
	ManagedArrElementAccessor32S(ManagedImage^ image) : ManagedArrElementAccessorBase<int>(image) {}
};

public ref class ManagedArrElementAccessor32F : ManagedArrElementAccessorBase<float>
{
public:
	ManagedArrElementAccessor32F(ManagedMat^ mat) : ManagedArrElementAccessorBase<float>(mat) {}
	ManagedArrElementAccessor32F(ManagedImage^ image) : ManagedArrElementAccessorBase<float>(image) {}
};

public ref class ManagedArrElementAccessor64F : ManagedArrElementAccessorBase<double>
{
public:
	ManagedArrElementAccessor64F(ManagedMat^ mat) : ManagedArrElementAccessorBase<double>(mat) {}
	ManagedArrElementAccessor64F(ManagedImage^ image) : ManagedArrElementAccessorBase<double>(image) {}
};

//////////////////////////////////////////////////////////////////////////
NAMESPACE_END
//////////////////////////////////////////////////////////////////////////